package com.comprental.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.comprental.config.Constants;
import com.comprental.dto.LeasingCreditDTO;
import com.comprental.entity.LeasingCredit;
import com.comprental.mapper.LeasingCreditMapper;
import com.comprental.utils.PopHttpClientUtil;
import com.comprental.utils.R;
import com.comprental.utils.SignUtil;
import com.comprental.utils.XMathUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @Author: zhangjun
 * @Date: 2020/8/17 9:37
 * @Description: 信用租赁-商户对接 服务层
 */
@Service
@AllArgsConstructor
public class LeasingCreditService extends ServiceImpl<LeasingCreditMapper, LeasingCredit> {
    private LeasingCreditMapper leasingCreditMapper;
    /**
     * 保存平台请求授信信息
     */
    public R saveLeasingCredit(LeasingCreditDTO creditDTO) throws JsonProcessingException {
        /*String sign = createSign(creditDTO.getMethod(), creditDTO.getOrderId());
        if (!Objects.equals(sign, creditDTO.getSign())) {
            return R.error("请求参数不合法");
        }*/

        //检查是否已经存在该订单
        LeasingCredit dbCredit = getLeasingCredit(creditDTO.getOrderId(), creditDTO.getUid());
        LeasingCredit leasingCredit = new LeasingCredit();
        BeanUtils.copyProperties(creditDTO, leasingCredit);

        if (Objects.isNull(dbCredit)) { //新增
            DefaultIdentifierGenerator identifierGenerator = new DefaultIdentifierGenerator();
            leasingCredit.setId(identifierGenerator.nextId(leasingCredit));
            leasingCredit.setCreateDate(new Date());
            leasingCredit.setUpdateDate(new Date());
            leasingCredit.setEstimateRentBeginTime(parseDate(creditDTO.getEstimateRentBeginTime()));
            leasingCredit.setEstimateRentEndTime(parseDate(creditDTO.getEstimateRentEndTime()));
            leasingCredit.setApplicationTime(parseDate(creditDTO.getApplicationTime()));
            leasingCreditMapper.insert(leasingCredit);
        } else { //更新记录
            LambdaQueryWrapper<LeasingCredit> wrapper = new LambdaQueryWrapper<LeasingCredit>();
            wrapper.eq(LeasingCredit::getId,dbCredit.getId());
            leasingCredit.setUpdateDate(new Date());
            update(leasingCredit, wrapper);
        }

        String msg = callBack(creditDTO);
        ObjectMapper mapper = new ObjectMapper();
        Map msgMap =  mapper.readValue(msg, Map.class);
        Map resMap =  MapUtils.getMap(msgMap,"rent_credit_callback_response");
        Map rentMap =  MapUtils.getMap(resMap,"rent");
        if (Objects.equals(MapUtils.getLong(rentMap,"code"), Long.valueOf(0))) {
            return R.ok();
        } else {
            return R.error("授信失败");
        }
    }

    /**
     * 查询授信额度
     */
    public R queryCreditLine(LeasingCreditDTO creditDTO) {
        Map res = Maps.newHashMap();
        Integer uid = creditDTO.getUid();//MapUtils.getString(map,"uid");
        String orderId = creditDTO.getOrderId();//MapUtils.getString(map,"orderId");

        /*String sign = createSign(creditDTO.getMethod(), creditDTO.getOrderId());
        if (!Objects.equals(sign, creditDTO.getSign())) {
            return R.error("请求参数不合法");
        }*/

        LeasingCredit dbCredit = getLeasingCredit(orderId, uid);
        if (!Objects.isNull(dbCredit)) {
            BeanUtils.copyProperties(dbCredit, creditDTO);
            res.put("creditStatusDesc","授信成功");
            res.put("totalDepositQuota",getLineOfCredit(creditDTO));
        }
        return R.ok(res);
    }

    /**
     * 授信公共方法
     */
    public R creditCallBack(LeasingCreditDTO creditDTO) throws JsonProcessingException {
        String method = creditDTO.getMethod();
        if (Objects.isNull(method)) {
            return R.error("请求接口类型不为空");
        }
        if (Objects.equals(method, Constants.CREDIT_SUBMIT_KEY)) {
            return saveLeasingCredit(creditDTO);
        }
        if (Objects.equals(method, Constants.CREDIT_QUERY_KEY)) {
            return queryCreditLine(creditDTO);
        }
        return R.error("非法请求类型");
    }

    /**
     * 授信完成回调平台
     */
    private String callBack(LeasingCreditDTO creditDTO) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("order_id", creditDTO.getOrderId());
        jsonObject.put("method", "fenqile.rent.credit.callback");
        jsonObject.put("uid", creditDTO.getUid());
        jsonObject.put("merchant_id", Constants.MERCHANT_ID);
        jsonObject.put("partner_id", Constants.PARTNER_ID);
        jsonObject.put("credit_status_desc", "授信成功");
        jsonObject.put("total_deposit_quota", getLineOfCredit(creditDTO));
        jsonObject.put("sign", createSign(jsonObject));
        String response = "";
        try {
            response = PopHttpClientUtil.postJson(jsonObject.toJSONString(), Constants.API_URL);
        } catch (Exception e) {
            System.err.print(response);
        }
        return response;
    }

    /**
     * 计算签名
     */
    private String createSign(JSONObject jsonObject) {
        Long timestamp = new Date().getTime() / 1000;
        jsonObject.put("format", "json");
        jsonObject.put("timestamp", timestamp);
        jsonObject.put("v", "1.4");
        return SignUtil.getSign(jsonObject.toJSONString(),Constants.PARTNER_KEY);
    }

    /**
     * 计算最终 授信额度
     * 风险等级：
     *  A额度80%
     *  B额度20%，
     *  C额度给0，
     *  D直接额度降为0，
     */
    private Long getLineOfCredit(LeasingCreditDTO creditDTO) {
        Long creditLimit = 0l;
        if (Objects.equals(creditDTO.getRiskLevel(), Constants.USER_RISK_LEVEL_A)) {
            creditLimit = XMathUtil.multiply(BigDecimal.valueOf(creditDTO.getEstimateCreditLimit()), BigDecimal.valueOf(0.8))
                    .setScale(0, BigDecimal.ROUND_DOWN).longValue();
        } else if (Objects.equals(creditDTO.getRiskLevel(), Constants.USER_RISK_LEVEL_B)) {
            creditLimit = XMathUtil.multiply(BigDecimal.valueOf(creditDTO.getEstimateCreditLimit()), BigDecimal.valueOf(0.2))
                    .setScale(0, BigDecimal.ROUND_DOWN).longValue();
        } else if (Objects.equals(creditDTO.getRiskLevel(), Constants.USER_RISK_LEVEL_C)) {
            creditLimit = XMathUtil.multiply(BigDecimal.valueOf(creditDTO.getEstimateCreditLimit()), BigDecimal.valueOf(0))
                    .setScale(0, BigDecimal.ROUND_DOWN).longValue();
        } else if (Objects.equals(creditDTO.getRiskLevel(), Constants.USER_RISK_LEVEL_D)) {
            creditLimit = XMathUtil.multiply(BigDecimal.valueOf(creditDTO.getEstimateCreditLimit()), BigDecimal.valueOf(0))
                    .setScale(0, BigDecimal.ROUND_DOWN).longValue();;
        } else {
            throw new RuntimeException("风险等级不合法");
        }
        return Objects.equals(creditLimit, Long.valueOf(0)) ? 1000l : creditLimit;
    }

    /**
     * 查询 授信消息
     */
    private LeasingCredit getLeasingCredit(String orderId, Integer uid) {
        LambdaQueryWrapper<LeasingCredit> wrapper = new LambdaQueryWrapper<LeasingCredit>();
        wrapper.eq(LeasingCredit::getOrderId,orderId);
        wrapper.eq(LeasingCredit::getUid,uid);
        wrapper.orderByDesc(LeasingCredit::getCreateDate);
        LeasingCredit dbCredit = getOne(wrapper);
        return dbCredit;
    }

    public static Date parseDate(String date) {
        /*SimpleDateFormat sdf = new SimpleDateFormat("MMM d, yyyy K:m:s a", Locale.ENGLISH);
        Date d2 = null;
        try {
            //把Jul 8, 2020 12:00:00 AM格式转换为常规的Date格式
            d2 = sdf.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }*/
        long time = Long.parseLong(date);
        Date d2 = new Date(time);

        return d2;
    }

}
